package com.to8to.autotask.countdown;

import static com.to8to.autotask.util.AutoTaskType.COUNTDOWN;
import static com.to8to.autotask.util.AutoTaskType.GENERATE_REBATERECORD;
import static com.to8to.autotask.util.DBOperaType.UPDATE;
import static com.to8to.es.db.dao.DBTables.TABLE_ZB;
import static com.to8to.thrift.crm.commons.commonsConstants.NODE_DJS25;
import static com.to8to.thrift.crm.commons.commonsConstants.NODE_DJS30;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.elasticsearch.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.to8to.autotask.resulthandler.FailHandler;
import com.to8to.autotask.rpc.CallClient;
import com.to8to.autotask.rpc.SendMsg2ES;
import com.to8to.autotask.rpc.SendSMSClient;
import com.to8to.autotask.util.DBUtil;
import com.to8to.autotask.util.Utils;
import com.to8to.autotask.zbinfo.ZBInfo;
import com.to8to.es.util.LogUtil;

/**
 * CountDownTask.java
 * 作 者：atom.liu
 * 版 本：v2.0
 * 日 期：2014年12月1日
 * 描 述：自动倒计时任务。
 *     竣工验收成功之后，从30天开始倒计时，每天执行一次减去一天，如果倒计时到0的时候，则自动生成返款记录，供财务审核（不直接执行返款）。
 *      2015-01-21 去掉初始化30天的情况，由监理点击验收成功时，直接修改 modify by atom.liu
 */
public class CountDownTask implements Runnable
{
    /**
     * SQL：查询出竣工的中标记录
     * jg_time > 0：已经竣工
     * syfktime > 0：倒计时天数大于0
     * yzbty != 1 ：用户没有暂停倒计时。
     * zxbyh = 1 :只针对装修保 
     * iscostbzj = 1:保障金是已交的状态。如果保证金是已退或者未交的状态就没有意义了。
     * gcjd = 5 : 工程进度是竣工
     * frozen = 0 : 没有被冻结
     * cputtime >= 1386086400 通过审核时间在2013年12月4号之后的项目才参与倒计时
     * gcjddetail != 63 业主还没有同意付款。 
     */
    private static final String JG_SQL =
        "select * from to8to_jj_smt_zb where jg_time > 0 and syfktime >= 0 and yzbty != 1 and zxbyh = 1 and iscostbzj = 1 and gcjd = 5 and frozen = 0 and cputtime >= 1386086400 and gcjddetail != 63";

    /**
     * 2015-03-05 syfktime 条件设置为0 ，当满足这些条件，但是syfktime居然还是为0，说明在其他地方未将syfktime初始化为30，这里做一个容错，当syfktime为0时，更新为30
     */
    private static final String NEED_FIX_SQL =
        "select * from to8to_jj_smt_zb where jg_time > %s and syfktime = 0 and yzbty != 1 and zxbyh = 1 and iscostbzj = 1 and gcjd = 5 and frozen = 0 and cputtime >= 1386086400 and gcjddetail != 63";

    /**
     * 将满足条件的syfktime 设置为30
     */
    private static final String UPDATE_FIX_SQL = "update to8to_jj_smt_zb set syfktime = 30, gcjddetail = 61 where zid in (%s) and syfktime = 0";

    /**
     * SQL：更新倒计时剩余天数(当前倒计时天数减去1)
     */
    private static final String UPATE_SQL =
        "update to8to_jj_smt_zb set syfktime = syfktime-1, gcjddetail = 61 where zid in (%s) and syfktime > 0 and yzbty != 1 and zxbyh = 1 and iscostbzj = 1  and gcjddetail != 63";

    private static final Logger logger = LoggerFactory.getLogger(CountDownTask.class);

    @Override
    public void run()
    {
        logger.info("自动倒计时任务开始执行...");

        Connection connect = null;

        try
        {
            connect = DBUtil.getConnection(false);

            if (DBUtil.execTaskCountsAtToday(connect, COUNTDOWN) != 0)
                return;

            List<String> updateZBList = Lists.newArrayList(); //需要更新倒计时剩余天数的中标id
            List<ZBInfo> rebateZBList = Lists.newArrayList(); //需要生成返款记录的中标记录
            List<Integer> sendMsg_remain5 = Lists.newArrayList(); //倒计时剩余5天的时候，要发送短信的手机号集合
            List<Integer> sendMsg_remain0 = Lists.newArrayList(); //倒计时剩余0天的时候，要发送短信的手机号集合
            PreparedStatement stat = connect.prepareStatement(JG_SQL);
            ResultSet result = stat.executeQuery();
            while (result.next())
            {
                ZBInfo info = new ZBInfo();
                int zid = result.getInt("zid");
                info.setUid(result.getInt("uid"));
                info.setYid(result.getInt("yid"));
                info.setZid(zid);

                updateZBList.add(String.valueOf(zid));
                if (result.getInt("syfktime") == 1)
                {
                    rebateZBList.add(info);
                    sendMsg_remain0.add(zid);
                }
                if (result.getInt("syfktime") == 6)
                    sendMsg_remain5.add(zid);
            }
            DBUtil.releaseSource(result, stat, null);

            //获取需要修复syfktime的中标id
            List<String> init30List = getNeedFixZB(connect);

            if (Utils.isNullOrEmpty(updateZBList) && Utils.isNullOrEmpty(init30List))
            {
                logger.info("本次没有需要倒计时的记录！");
                return;
            }

            logger.info(String.format("倒计时剩余0天的中标id：%s \r\n倒计时剩余5天的中标id ：%s", sendMsg_remain0, sendMsg_remain5));

            update(connect, updateZBList, init30List);
            if (DBUtil.execTaskCountsAtToday(connect, GENERATE_REBATERECORD) != 0)
                return;
            recordLog(connect, rebateZBList);
            CallClient.generateRebateRecord(rebateZBList);

            SendSMSClient.sendMsgWithZid(NODE_DJS30, sendMsg_remain0);
            SendSMSClient.sendMsgWithZid(NODE_DJS25, sendMsg_remain5);

            logger.info("自动倒计时任务执行结束...");
        }
        catch (Throwable e)
        {
            logger.error("自动倒计时任务出现异常！{} \n {}", e, LogUtil.logStackTrace(e));
            DBUtil.rollback(connect);
            if (e instanceof SQLException)
                FailHandler.handler(CountDownTask.class);
        }
        finally
        {
            DBUtil.releaseSource(null, null, connect);
        }
    }

    /**
     * 获得需要修复syfktime的中标记录
     */
    private List<String> getNeedFixZB(Connection connect) throws SQLException
    {
        List<String> list = Lists.newArrayList();
        int time = (int) (System.currentTimeMillis() / 1000) - 29 * 24 * 60 * 60; //当前时间减去jg_time小于29天
        PreparedStatement stat = connect.prepareStatement(String.format(NEED_FIX_SQL, time));
        ResultSet result = stat.executeQuery();
        while (result.next())
            list.add(String.valueOf(result.getInt("zid")));
        DBUtil.releaseSource(result, stat, null);
        return list;
    }

    /**
     * 记录生成返款信息
     */
    private void recordLog(Connection connect, List<ZBInfo> rebateZBList)
    {
        if (Utils.isNullOrEmpty(rebateZBList))
            return;
        List<String> sqls = Lists.newArrayList();
        sqls.add("本次要调用生成返款记录的信息：");
        for (ZBInfo info : rebateZBList)
            sqls.add(zbInfo2String(info));
        DBUtil.recordAutoTaskLog(connect, GENERATE_REBATERECORD, sqls, true);
    }

    /**
     * 更新信息到数据库 
     */
    private void update(Connection connect, List<String> updateZBList, List<String> init30List) throws SQLException
    {
        List<String> sqls = Lists.newArrayList();
        sqls.add(String.format(UPATE_SQL, Utils.collect2Str(updateZBList)));
        if (init30List.size() > 0)
        {
            updateZBList.addAll(init30List);
            String str = Utils.collect2Str(init30List);
            sqls.add(String.format(UPDATE_FIX_SQL, str));
            logger.info(String.format("本次倒计时需要修复syfktime的中标记录：[%s]", str));
        }

        DBUtil.refresh2DB(connect, sqls, COUNTDOWN, new SendMsg2ES(UPDATE, TABLE_ZB, updateZBList));
    }

    private String zbInfo2String(ZBInfo info)
    {
        StringBuilder sb = new StringBuilder();
        sb.append("zid:").append(info.getZid());
        sb.append(" uid:").append(info.getUid());
        sb.append(" yid:").append(info.getYid());
        return sb.toString();
    }
}
